/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include "AppTask.h"
#include "esp_log.h"
#include "cJSON.h"
#include <app_uart.h>
#include <sstream>
#include "app_mqtt_util.h"
#include "app_uart_util.h"
#include "app_ota.h"

#include "Button.h"
#include "LEDWidget.h"

#include <system/SystemClock.h>
#include <platform/CHIPDeviceLayer.h>
#include <app/server/Server.h>
#include <app/clusters/door-lock-server/door-lock-server.h>

#include "lockly_c_header.h"
#include "uart_util.h"
#include "driver/gpio.h"

#include <esp_matter.h>
#include <esp_matter_core.h>
#include <esp_matter_bridge.h>

#include <app_bridged_device.h>
#include "rf_sensor.h"
#include "app_ecdh.h"
#include "esp_heap_caps.h"
#include <time.h>
#include "lock_event_def.h"
#include "app_pair.h"

/* BLE */
#include "esp_central.h"


#define APP_TASK_NAME "Matter_Bridge"


#define BLEScanTimeout_MS 30000


#define SYSTEM_STATE_LED GPIO_NUM_18
#define SYSTEM_STATE_LED_GREEN GPIO_NUM_19

#define APP_FUNCTION_BUTTON GPIO_NUM_26
#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50

#define FACTORY_RESET_TRIGGER_TIMEOUT 2000
#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 1000
#define FACTORY_RESET_BUTTON_AVAIABLE_WINDOW 15000 //Change to 20 seconds for factory reset button available window

#define SERVER_INIT_WINDOW 300000


#define APP_EVENT_QUEUE_SIZE 20
#define APP_TASK_STACK_SIZE (6656)
#define APP_TASK_PRIORITY 4

#define LOCK_STATUS_BIT 1
#define HAS_WIRED_DS_BIT 2
#define WIRED_DS_STATUS_BIT 4
#define HAS_RF_DS_BIT 8
#define HAS_RF_STATUS_BIT 16
#define SECURE_MODE_BIT 32
#define SECURE_LOCK_BIT 64
#define LOW_BAT_BIT 128

static const char * const TAG = "App-Task";

static const char * const GATTC_TAG = "GATT-TAG";

extern "C" {
    void ble_scan_status_debug(void);
	void read_freq_chal(void);	
	void Set_Frequece_Init(void);	
	uint8_t get_current_chal(void);
}


namespace {

TimerHandle_t sScanDevTimer;
TimerHandle_t sRestartTimer;
TimerHandle_t sInitWatchdogTimer;



BaseType_t sAppTaskHandle;
QueueHandle_t sAppEventQueue;


StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)];
} // namespace

using namespace ::chip::DeviceLayer;
using namespace ::chip::System;
using namespace ::chip::System::Clock;
using namespace ::chip::app::Clusters::DoorLock;
using namespace esp_matter;


AppTask AppTask::sAppTask;
static uint32_t alloc_failed_count=0;
bool isIdentifying = 0;
static bool startedWifiProvioning = 0;

uint32_t get_alloc_failed_count(void)
{
	return alloc_failed_count;
}

esp_err_t AppTask::StartAppTask()
{
    sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent));
    if (sAppEventQueue == NULL)
    {
        ESP_LOGE(TAG, "Failed to allocate app event queue"); 
        return ESP_FAIL;
    }

    // Start App task.
    sAppTaskHandle = xTaskCreate(AppTaskMain, APP_TASK_NAME, ArraySize(appStack), NULL, APP_TASK_PRIORITY, NULL);
    return sAppTaskHandle ? ESP_OK : ESP_FAIL;
}

void SetHubId(void)
{
	if(!ConnectivityMgr().IsWiFiStationProvisioned()){
		ESP_LOGI(TAG, "SetBLEDeviceName");
		//Note: kMaxDeviceNameLength should be changed to 32
		ConnectivityMgr().SetBLEDeviceName(get_hub_id());						
		ConnectivityMgr().SetBLEAdvertisingEnabled(true);			
		ConnectivityMgr().SetBLEAdvertisingMode(ConnectivityMgr().kFastAdvertising);
	}			
}

void heap_caps_alloc_failed_hook(size_t requested_size, uint32_t caps, const char *function_name)
{
    alloc_failed_count++;
    printf("%s was called but failed to allocate %d bytes with 0x%" PRIX32 " capabilities. \n",function_name, requested_size, caps);
    ESP_LOGE(TAG, "free heap size is %" PRIu32 ", minimum %" PRIu32, esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
    if(is_mqtt_connected&&alloc_failed_count>5){
       ESP_LOGE(TAG, "Memory is too low, restarting...");
	   GetAppTask().AppScheduleWork(restartAfterProvisioning, NULL); 
    }
}

esp_err_t AppTask::Init()
{
	esp_err_t err = ESP_OK;
    // Create FreeRTOS sw timer for Function Selection

    sScanDevTimer = xTimerCreate("ScanDevTmr",          // Just a text name, not used by the RTOS kernel
                                  10000/portTICK_PERIOD_MS,                // == default timer period (mS)
                                  true,            // timer reload (==one-shot)
                                  (void *) this,    // init timer id = app task obj context
                                  ScanDevTimerEventHandler // timer callback handler
    );
	sRestartTimer = xTimerCreate(
    							"RestartTimer",             // Just a text name, not used by the RTOS kernel
    							pdMS_TO_TICKS(1800000),     // Set timer period to 3 minutes
								//aTimeoutInMs,     // Set timer period to 2 minutes
    							false,                    // Auto start
    							(void *)0,                  // The id is not used, so can be set to anything
    							RestartTimerEventHandler        // The callback function that inspects the status of all the other tasks
	);
	sInitWatchdogTimer = xTimerCreate(
    							"InitWatchdogTimer",             // Just a text name, not used by the RTOS kernel
								pdMS_TO_TICKS(300000),     // Set timer period to 5 minutes
    							false,                    // The timer will not auto-reload itself when it expires
    							(void *)0,                  // The id is not used, so can be set to anything
    							InitWatchdogEventHandler        // The callback function that inspects the status of all the other tasks
	);


    ble_diagnose_init();
	ESP_LOGI(TAG, "Activated ble diagnose!!!");
	err = hub_info_init();
	InitialiseHubAttributes();
	if(err!=ESP_OK){		
		ESP_LOGI(TAG, "Didn't Flash MFG Data");
	}
	DeviceLayer::PlatformMgr().ScheduleWork(SetHubId, NULL); 
	heap_caps_register_failed_alloc_callback(heap_caps_alloc_failed_hook);
    return err;
}



void printTaskInfo()
{
    // Allocate a buffer to store task details
    TaskStatus_t *taskArray;
    volatile UBaseType_t taskCount;
    uint32_t totalRunTime;

    // Get the number of tasks
    taskCount = uxTaskGetNumberOfTasks();

    // Allocate a TaskStatus_t structure for each task
    taskArray = (TaskStatus_t *)pvPortMalloc(taskCount * sizeof(TaskStatus_t));

    if (taskArray != NULL)
    {
        // Get the task status information
        taskCount = uxTaskGetSystemState(taskArray, taskCount, &totalRunTime);

        // Print each task's information
        for (UBaseType_t i = 0; i < taskCount; i++)
        {
			// ESP_LOGI("Task Info", "Task: %s, Stack High Water Mark: %u"//, Runtime: %d",
            //          taskArray[i].pcTaskName, 
            //          taskArray[i].usStackHighWaterMark, 
            //          taskArray[i].ulRunTimeCounter);
			printf("Task: %s, Stack High Water Mark: %" PRIu32 ", Runtime: %" PRIu32 "\n",
                   taskArray[i].pcTaskName, 
                   taskArray[i].usStackHighWaterMark, 
                   taskArray[i].ulRunTimeCounter);

        }

        // Free the allocated memory
        vPortFree(taskArray);
    }
}

void printHeapInfo()
{
    char buffer[256];
    sprintf(buffer, "\t /     Free /    Total\n"
                    " SRAM : [/ %8d / %8d]\n"
                    "PSRAM : [/ %8d / %8d]\n",
            // heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL),
            heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
            heap_caps_get_total_size(MALLOC_CAP_INTERNAL),
            // heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM),
            heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
            heap_caps_get_total_size(MALLOC_CAP_SPIRAM));
    printf("------------ Memory ------------\n");
    printf("%s", buffer);
    printf("low watermarks of SRAM : %d \r\n", heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL));
    printf("low watermarks of PSRAM : %d \r\n", heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
    printf(".esp_get_free_heap_size = %ld\n\r", esp_get_free_heap_size());
}

void AppTask::AppTaskMain(void * pvParameter)
{
    AppEvent event;
    Clock::Timestamp lastChangeTime = Clock::kZero;
    esp_err_t err = sAppTask.Init();
    if (err != ESP_OK)
    {
        ESP_LOGI(TAG, "AppTask.Init() failed");
        return;
    }
    ESP_LOGI(TAG, "App Task started");
	if(ConnectivityMgr().IsWiFiStationProvisioned()){
		ESP_LOGE(TAG, "WiFi is provisioned");
        closeMatterCommissioningWindows();  // 已经配过网了
		startedWifiProvioning = false;
		if(sInitWatchdogTimer)
			xTimerStart(sInitWatchdogTimer, 0); //Start watchdog timer to check if the mqtt can be connected in 5 minutes

	}else{
		ESP_LOGE(TAG, "WiFi is NOT provisioned");		
		startedWifiProvioning = true;
	}	

    while (true)
    {
        BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, 10/portTICK_PERIOD_MS);
        while (eventReceived == pdTRUE)
        {
            sAppTask.DispatchEvent(&event);
            eventReceived = xQueueReceive(sAppEventQueue, &event, 0);
            vTaskDelay(pdMS_TO_TICKS(10)); // 让出 CPU, 给看门狗重置的机会
        }

        if (chip::Server::GetInstance().GetCommissioningWindowManager().IsCommissioningWindowOpen())
        {
            static bool bleConnectFlag = 0;
            GetAppTask().PostBlePairForWifiConnect();
            // if(ConnectivityMgr().IsWiFiStationConnected())
            if (PlatformMgr().TryLockChipStack())
            {
                // ble 连接后
                if (ConnectivityMgr().NumBLEConnections())
                {
                    bleConnectFlag = true;
                }
                // ble 连接又断开后，表示配网事件结束，关闭配网窗口
                if (bleConnectFlag)
                {
                    if (!ConnectivityMgr().NumBLEConnections())
                    {
                        closeMatterCommissioningWindows();
                        bleConnectFlag = false;
                    }
                }
                PlatformMgr().UnlockChipStack();
            }
        }

        Clock::Timestamp now			= SystemClock().GetMonotonicTimestamp();
		Clock::Timestamp nextChangeTime = lastChangeTime + Clock::Seconds16(5);
	
		if (nextChangeTime < now)
		{
			lastChangeTime = now;			
			uint64_t timestamp = get_timestamp_ms();
			if(ConnectivityMgr().IsWiFiStationProvisioned()){
				GetAppTask().MonitorOnlinestatus();		
				CheckRFsensorTimeout();
			}
    		ESP_LOGE(TAG, "free sram heap size is %d , minimum %d", heap_caps_get_free_size(MALLOC_CAP_INTERNAL),heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL));
            ESP_LOGE(TAG, "free psram heap size is %d , minimum %d", heap_caps_get_free_size(MALLOC_CAP_SPIRAM), heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));            
            // printHeapInfo();
		}
		CheckRFsensorState();
    }
}

static int blecent_gap_event(struct ble_gap_event *event, void *arg);
/**
 * Initiates the GAP general discovery procedure.
 */
static void
blecent_scan(void)
{
    uint8_t own_addr_type;
    struct ble_gap_disc_params disc_params;
    int rc;

    /* Figure out address to use while advertising (no privacy for now) */
    rc = ble_hs_id_infer_auto(0, &own_addr_type);
    if (rc != 0) {
        MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
        return;
    }

    /* Tell the controller to filter duplicates; we don't want to process
     * repeated advertisements from the same device.
     */
    disc_params.filter_duplicates = 0;

    /**
     * Perform a passive scan.  I.e., don't send follow-up scan requests to
     * each advertiser.
     */
    disc_params.passive = 1;

    /* Use defaults for the rest of the parameters. */
    disc_params.itvl = 0;
    disc_params.window = 0;
    disc_params.filter_policy = 0;
    disc_params.limited = 0;

    rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
                      blecent_gap_event, NULL);
    if (rc != 0) {
        MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
                    rc);
    }
}
/*
#ifdef CONFIG_BT_BLUEDROID_ENABLED
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    uint8_t *adv_name = NULL;
    uint8_t adv_name_len = 0;
    switch (event) {
    case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
        //the unit of the duration is second
        uint32_t duration = BLEScanTimeout_MS/1000;
        esp_ble_gap_start_scanning(duration);
        break;
    }
    case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
        //scan start complete event to indicate scan start successfully or failed
        if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
            ESP_LOGE(GATTC_TAG, "scan start failed, error status = %x", param->scan_start_cmpl.status);
            break;
        }
        ESP_LOGI(GATTC_TAG, "scan start success");

        break;
    case ESP_GAP_BLE_SCAN_RESULT_EVT: {
        esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
        switch (scan_result->scan_rst.search_evt) {
        case ESP_GAP_SEARCH_INQ_RES_EVT:
          //  esp_log_buffer_hex(GATTC_TAG, scan_result->scan_rst.bda, 6);
          //  ESP_LOGI(GATTC_TAG, "searched Adv Data Len %d, Scan Response Len %d", scan_result->scan_rst.adv_data_len, scan_result->scan_rst.scan_rsp_len);
            adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv,
                                                ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);

            if (adv_name != NULL) {
				
				uint8_t *manufacture_data = NULL;
				uint8_t manufacture_data_len = 0;
				manufacture_data = esp_ble_resolve_adv_data(param->scan_rst.ble_adv, ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE, &manufacture_data_len);
				if(manufacture_data_len>16){					
					app_bridged_device_t *device;
					device = app_bridge_get_device_by_espnow_macaddr(param->scan_rst.bda);
					if(device){
						if(device->dev_info.device_status != manufacture_data[3])
						{						
							ESP_LOGI(GATTC_TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", ESP_BD_ADDR_HEX(param->scan_rst.bda));
							ESP_LOGI(GATTC_TAG, "manufacture_data_len = %d", manufacture_data_len);
							device->dev_info.device_status = manufacture_data[3];													
							esp_log_buffer_hex(GATTC_TAG,manufacture_data,manufacture_data_len);	
							DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockAttribute, reinterpret_cast<intptr_t>(device));
						}
					}
				}						
            }
            break;
        case ESP_GAP_SEARCH_INQ_CMPL_EVT:
            break;
        default:
            break;
        }
        break;
    }

    case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
        if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
            ESP_LOGE(GATTC_TAG, "scan stop failed, error status = %x", param->scan_stop_cmpl.status);
            break;
        }
        ESP_LOGI(GATTC_TAG, "stop scan successfully");
        break;

    case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
        if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
            ESP_LOGE(GATTC_TAG, "adv stop failed, error status = %x", param->adv_stop_cmpl.status);
            break;
        }
        ESP_LOGI(GATTC_TAG, "stop adv successfully");
        break;
    case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
         ESP_LOGI(GATTC_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
                  param->update_conn_params.status,
                  param->update_conn_params.min_int,
                  param->update_conn_params.max_int,
                  param->update_conn_params.conn_int,
                  param->update_conn_params.latency,
                  param->update_conn_params.timeout);
        break;
    default:
        break;
    }
}
#endif
*/
// 连接锁端蓝牙模块
void blecent_should_connect_yuezheng(void)
{
    uint8_t own_addr_type;
    ble_addr_t peer_addr;
    int rc;
    uint8_t addr_val[6] = {0x25, 0xed, 0xe2, 0x36, 0xce, 0xf4};


    /* Scanning must be stopped before a connection can be initiated. */
    rc = ble_gap_disc_cancel();
    if (rc != 0) {
        MODLOG_DFLT(DEBUG, "Failed to cancel scan; rc=%d\n", rc);
        return;
    }

    peer_addr.type = BLE_ADDR_PUBLIC; 
    memcpy(peer_addr.val, addr_val, sizeof(addr_val));

    rc = ble_gap_connect(BLE_OWN_ADDR_RANDOM, &peer_addr, 30000, NULL,
                         blecent_gap_event, NULL);
    if (rc != 0)
    {
        MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d "
                           "addr=%s; rc=%d\n",
                    peer_addr.type, addr_str(peer_addr.val), rc);
        return;
    }
}



static int
blecent_on_subscribe(uint16_t conn_handle,
                     const struct ble_gatt_error *error,
                     struct ble_gatt_attr *attr,
                     void *arg)
{
    struct peer *peer;
    const struct peer_chr *chr;
    int rc;
    MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d "
                "attr_handle=%d\n",
                error->status, conn_handle, attr->handle);

    peer = peer_find(conn_handle);
    if (peer == NULL) {
        MODLOG_DFLT(ERROR, "Error in finding peer, aborting...");
        ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
    }
    /* Subscribe to, write to, and read the custom characteristic*/
    // blecent_custom_gatt_operations(peer);


    peer = peer_find(conn_handle);
    chr = peer_chr_find_uuid(peer,
                             BLE_UUID16_DECLARE(0xFFF0),
                             BLE_UUID16_DECLARE(0xFFF1));


    // 发送唤醒指令
    uint8_t rssi_data[9] = {0xA1,0xB2,0xC3,0xD4,0x09,0x00,0x01,0x0F,0xF3};
    rc = ble_gattc_write_flat(conn_handle, chr->chr.val_handle,
                              &rssi_data, sizeof(rssi_data), NULL, NULL);
    MODLOG_DFLT(INFO, "write 0xfff1 rc = %d",rc);
    return 0;
}


static void subscribe_notify(const struct peer *peer)
{

    const struct peer_dsc *dsc;
    int rc;
    uint8_t value[2];

    dsc = peer_dsc_find_uuid(peer,
                             BLE_UUID16_DECLARE(0xFFF0),
                             BLE_UUID16_DECLARE(0xFFF4),
                             BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16));


    value[0] = 1;
    value[1] = 0;
    rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle,
                              value, sizeof value, blecent_on_subscribe, NULL);
}

/**
 * Called when service discovery of the specified peer has completed.
 */
static void
blecent_on_disc_complete(const struct peer *peer, int status, void *arg)
{

    if (status != 0) {
        /* Service discovery failed.  Terminate the connection. */
        MODLOG_DFLT(ERROR, "Error: Service discovery failed; status=%d "
                    "conn_handle=%d\n", status, peer->conn_handle);
        ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
        return;
    }

    /* Service discovery has completed successfully.  Now we have a complete
     * list of services, characteristics, and descriptors that the peer
     * supports.
     */
    MODLOG_DFLT(INFO, "Service discovery complete; status=%d "
                "conn_handle=%d\n", status, peer->conn_handle);


    // 使能 0xFFF4 的 notify
    subscribe_notify(peer);
}

#ifdef CONFIG_BT_NIMBLE_ENABLED
static int blecent_gap_event(struct ble_gap_event *event, void *arg)
{
    struct ble_hs_adv_fields fields;
    int rc;	
	app_bridged_device_t *device;
	uint8_t espnow_macaddr[6];
	struct ble_gap_conn_desc desc;
    switch (event->type) {
    case BLE_GAP_EVENT_DISC:
			espnow_macaddr[0] = event->disc.addr.val[5];
			espnow_macaddr[1] = event->disc.addr.val[4];
			espnow_macaddr[2] = event->disc.addr.val[3];
			espnow_macaddr[3] = event->disc.addr.val[2];
			espnow_macaddr[4] = event->disc.addr.val[1];
			espnow_macaddr[5] = event->disc.addr.val[0];
			device = app_bridge_get_device_by_espnow_macaddr(espnow_macaddr);
			/*
			if(device){
			 	ESP_LOGE(GATTC_TAG, "Found Device (bda): %02x:%02x:%02x:%02x:%02x:%02x", event->disc.addr.val[5],\
			 		event->disc.addr.val[4],event->disc.addr.val[3],event->disc.addr.val[2],event->disc.addr.val[1],event->disc.addr.val[0]);						
			 	esp_log_buffer_hex(TAG,event->disc.data,event->disc.length_data);
			}
			*/

	        rc = ble_hs_adv_parse_fields(&fields, event->disc.data,
	                                     event->disc.length_data);
	        if (rc != 0) {
				if(device)
					ESP_LOGE(TAG, "Failed to parse advertisement data; rc=%d\n", rc);
	            return 0;
	        }/*else{
				// if(device){
				// 	ESP_LOGE(GATTC_TAG, "Found Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", event->disc.addr.val[5],\
				// 			event->disc.addr.val[4],event->disc.addr.val[3],event->disc.addr.val[2],event->disc.addr.val[1],event->disc.addr.val[0]);						
				// 	esp_log_buffer_hex(GATTC_TAG,fields.mfg_data,fields.mfg_data_len);	
				// }
			}*/
			if (fields.mfg_data_len>16){
				// app_bridged_device_t *device;
				// uint8_t espnow_macaddr[6];
				// espnow_macaddr[0] = event->disc.addr.val[5];
				// espnow_macaddr[1] = event->disc.addr.val[4];
				// espnow_macaddr[2] = event->disc.addr.val[3];
				// espnow_macaddr[3] = event->disc.addr.val[2];
				// espnow_macaddr[4] = event->disc.addr.val[1];
				// espnow_macaddr[5] = event->disc.addr.val[0];
				//device = app_bridge_get_device_by_espnow_macaddr(espnow_macaddr);		
				if(device){	
					device->dev_info.rssi= event->disc.rssi;					
					if((device->dev_info.is_online==false)||(get_timestamp_ms() - device->dev_info.last_update_time >120000)){
						device->dev_info.is_online = true;
						DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockReachableAttribute, reinterpret_cast<intptr_t>(device));
						GetAppTask().AppScheduleWork(PublishOnlineStatus, reinterpret_cast<intptr_t>(device));  					
					}
					device->dev_info.last_update_time = get_timestamp_ms();
					if(fields.mfg_data[2]==19){
						if(fields.mfg_data[21]==1){
							GetAppTask().AppScheduleWork(SendLockSyncTimeCommand, reinterpret_cast<intptr_t>(device)); 
						}
					}

					if(memcmp(device->dev_info.ble_broadcast_data,fields.mfg_data,fields.mfg_data_len))
					{
						ESP_LOGE(GATTC_TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", event->disc.addr.val[5],\
							event->disc.addr.val[4],event->disc.addr.val[3],event->disc.addr.val[2],event->disc.addr.val[1],event->disc.addr.val[0]);						
						// ESP_LOGI(GATTC_TAG, "manufacture_data_len = %d", fields.mfg_data_len);
						// esp_log_buffer_hex(GATTC_TAG,fields.mfg_data,fields.mfg_data_len);	
						device->dev_info.change_bit=0;
						if(device->dev_info.device_status!=fields.mfg_data[3]){			
							if((device->dev_info.device_status&0x01)!=(fields.mfg_data[3]&0x01))
								device->dev_info.change_bit |=DoorLockStatusBit;
							device->dev_info.last_change_time = get_timestamp_ms();
							if(fields.mfg_data[3]&0x02)
							{
								// to do .. find the wired sensor firstly								
								app_bridged_device_t *sensor = app_bridge_get_sensor_by_sensor_id("FFFFFF");
								if((sensor)&&((device->dev_info.device_status&0x04)!=(fields.mfg_data[3]&0x04))){
									if(fields.mfg_data[3]&0x04)
										sensor->dev_info.sensor_status = 1;		
									else
										sensor->dev_info.sensor_status = 2;							
									sensor->dev_info.last_change_time = get_timestamp_ms();	
									if(ENABLE_HOMEKIT_SENSOR)	
										DeviceLayer::PlatformMgr().ScheduleWork(UpdateDoorSensorAttribute, reinterpret_cast<intptr_t>(sensor));			
									else
										ESP_LOGE(TAG, "Sensor status is %d, HOMEKIT sesnor function is disabled.",sensor->dev_info.sensor_status);
									//Commented by Tony Wei. 2024.07.74
									//For wired sensor, no need to push sensor message. Only publish lock status, and let mbps to handel push message									
									//GetAppTask().AppScheduleWork(PublishDoorSensorStatus,  reinterpret_cast<intptr_t>(sensor)); 									
									//Commented by Tony Wei. 2024.07.74
									device->dev_info.change_bit |=DoorLockStatusBit;
									if(sensor->dev_info.is_online == false){
										sensor->dev_info.is_online = true;
										DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockReachableAttribute, reinterpret_cast<intptr_t>(sensor));
									}
								}
							}		

							ESP_LOGE(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", event->disc.addr.val[5],\
								event->disc.addr.val[4],event->disc.addr.val[3],event->disc.addr.val[2],event->disc.addr.val[1],event->disc.addr.val[0]);
							ESP_LOGE(TAG, "Old Status:%02x, New Status:%02x",device->dev_info.device_status,fields.mfg_data[3]);

							if(((device->dev_info.device_status&(SECURE_MODE_BIT | SECURE_MODE_BIT))!=(fields.mfg_data[3]&(SECURE_MODE_BIT | SECURE_MODE_BIT)))
							   ||((device->dev_info.device_status&LOW_BAT_BIT)!=(fields.mfg_data[3]&LOW_BAT_BIT))){
								if(fields.mfg_data[3]&(SECURE_MODE_BIT | SECURE_MODE_BIT))
								    ESP_LOGE(TAG, "Secure Mode is on");
								else
									ESP_LOGE(TAG, "Secure Mode is off");
									
								if(fields.mfg_data[3]&(LOW_BAT_BIT)){
									ESP_LOGE(TAG, "Low Battery");
								}
								else{
									ESP_LOGE(TAG, "Battery is normal");								
								}
								device->dev_info.change_bit |=DoorLockStatusBit;
							}

							if((device->dev_info.device_status&0x01)!=(fields.mfg_data[3]&0x01))
							{
								device->dev_info.device_status = fields.mfg_data[3];
								device->dev_info.reserve[0] = 0;
								device->dev_info.reserve[0] = 0;
								device->dev_info.reserve[0] = 0;
								DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockAttribute, reinterpret_cast<intptr_t>(device));
							}
							else
								device->dev_info.device_status = fields.mfg_data[3];							


						}
						if(memcmp(&device->dev_info.ble_broadcast_data[4],&fields.mfg_data[4],fields.mfg_data_len-4)){								
							device->dev_info.change_bit |=DoorlockEventBit;
						}
						memcpy(device->dev_info.ble_broadcast_data,fields.mfg_data,fields.mfg_data_len);						
						if(device->dev_info.change_bit)
							GetAppTask().AppScheduleWork(PublishDoorLockStatus, reinterpret_cast<intptr_t>(device));
					}else{
                        
                    /*
						ESP_LOGE(GATTC_TAG, "Data No Change: Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", event->disc.addr.val[5],\
							event->disc.addr.val[4],event->disc.addr.val[3],event->disc.addr.val[2],event->disc.addr.val[1],event->disc.addr.val[0]);						
						esp_log_buffer_hex(GATTC_TAG,fields.mfg_data,fields.mfg_data_len);
                    */
                        blecent_should_connect_yuezheng();  // 这里测试连接
					}
				}
			}
			else{
				//ESP_LOGE(GATTC_TAG, "No manufacture data");
				app_bridged_device_t *device;
				uint8_t espnow_macaddr[6];
				espnow_macaddr[0] = event->disc.addr.val[5];
				espnow_macaddr[1] = event->disc.addr.val[4];
				espnow_macaddr[2] = event->disc.addr.val[3];
				espnow_macaddr[3] = event->disc.addr.val[2];
				espnow_macaddr[4] = event->disc.addr.val[1];
				espnow_macaddr[5] = event->disc.addr.val[0];
				device = app_bridge_get_device_by_espnow_macaddr(espnow_macaddr);	
				if(device){
					device->dev_info.rssi= event->disc.rssi;					
					if((device->dev_info.is_online==false)||(get_timestamp_ms() - device->dev_info.last_update_time >120000)){
						device->dev_info.is_online = true;
						DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockReachableAttribute, reinterpret_cast<intptr_t>(device));
						GetAppTask().AppScheduleWork(PublishOnlineStatus, reinterpret_cast<intptr_t>(device));  					
					}		
					device->dev_info.last_update_time = get_timestamp_ms();
				}
			}
	
        return 0;

    case BLE_GAP_EVENT_DISCONNECT:
        /* Connection terminated. */
        MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
        print_conn_desc(&event->disconnect.conn);
        MODLOG_DFLT(INFO, "\n");

        /* Forget about peer. */
        peer_delete(event->disconnect.conn.conn_handle);

        /* Resume scanning. */
        blecent_scan();
        return 0;



    case BLE_GAP_EVENT_CONNECT:
        /* A new connection was established or a connection attempt failed. */
        if (event->connect.status == 0) {
            /* Connection successfully established. */
            MODLOG_DFLT(INFO, "Connection established ");

            rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
            assert(rc == 0);
            print_conn_desc(&desc);
            MODLOG_DFLT(INFO, "\n");

            /* Remember peer. */
            rc = peer_add(event->connect.conn_handle);
            if (rc != 0) {
                MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc);
                return 0;
            }

            /* Perform service discovery */
            rc = peer_disc_all(event->connect.conn_handle,
                        blecent_on_disc_complete, NULL);
            if(rc != 0) {
                MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
                return 0;
            }
        } else {
            /* Connection attempt failed; resume scanning. */
            MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n",
                        event->connect.status);
            blecent_scan();
        }

        return 0;
    case BLE_GAP_EVENT_NOTIFY_RX:
        /* Peer sent us a notification or indication. */
        MODLOG_DFLT(INFO, "received %s; conn_handle=%d attr_handle=%d "
                          "attr_len=%d\n",
                    event->notify_rx.indication ? "indication" : "notification",
                    event->notify_rx.conn_handle,
                    event->notify_rx.attr_handle,
                    OS_MBUF_PKTLEN(event->notify_rx.om));

        /* Attribute data is contained in event->notify_rx.om. Use
         * `os_mbuf_copydata` to copy the data received in notification mbuf */
        esp_log_buffer_hex("yuezheng.gao received data form pher", event->notify_rx.om->om_data, event->notify_rx.om->om_len);
        return 0;

    default:
        return 0;
    }
}


#endif

void AppTask::ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction)
{
    if (btnIdx != APP_FUNCTION_BUTTON)
    {
        return;
    }

    AppEvent button_event             = {};
    button_event.Type                = AppEvent::kEventType_Button;
    button_event.ButtonEvent.mPinNo  = btnIdx;
    button_event.ButtonEvent.mAction = btnAction;
    button_event.Handler = FunctionHandler;
    sAppTask.PostEvent(&button_event);

}

void AppTask::RestartTimerEventHandler(TimerHandle_t xTimer){
	// Call the function to restart the system
    ESP_LOGE(TAG, "----------Restarting the system in the timer callback-----------");
	esp_restart();
	
}

void AppTask::InitWatchdogEventHandler(TimerHandle_t xTimer){
	// Call the function to restart the system
    //esp_restart();
	if(is_mqtt_connected()){
		ESP_LOGE(TAG, "MQTT init success");
		ESP_LOGE(TAG, "Cancel watchdo timer");
		if (xTimerStop(sInitWatchdogTimer, 0) == pdFAIL)
		{
			ESP_LOGI(TAG, "InitWatchdog timer stop() failed");
		}
	}
	else{
		ESP_LOGE(TAG, "MQTT init failed");
		ESP_LOGE(TAG, "Restarting the system in the timer callback");
	}
}

void AppTask::ScanDevTimerEventHandler(TimerHandle_t xTimer)
{
    AppEvent event;
    event.Type                = AppEvent::kEventType_ScanDevTimer;
    event.TimerEvent.Context = (void *) xTimer;
    event.Handler             = ScanDevFunctionTimerEventHandler;
    sAppTask.PostEvent(&event);

}
void AppTask::ScanDevFunctionTimerEventHandler(AppEvent * aEvent)
{
#ifdef CONFIG_BT_BLUEDROID_ENABLED
	
    int ret = esp_ble_gap_register_callback(esp_gap_cb);
    if (ret){
        ESP_LOGE(TAG, "%s gap register failed, error code = %x\n", __func__, ret);
        return;
    }

    static esp_ble_scan_params_t ble_scan_params = {    .scan_type              = BLE_SCAN_TYPE_ACTIVE,
													    .own_addr_type          = BLE_ADDR_TYPE_PUBLIC,
													    .scan_filter_policy     = BLE_SCAN_FILTER_ALLOW_ALL,//BLE_SCAN_FILTER_ALLOW_ONLY_WLST,//BLE_SCAN_FILTER_ALLOW_ALL,
														.scan_interval          = 0x28,
														.scan_window            = 0x24};	
	

    int rc = esp_ble_gap_set_scan_params(&ble_scan_params);
    if (rc != 0)
    {
        ESP_LOGE(TAG, "esp_ble_gap_set_scan_params failed: %d", rc);
    }
#endif

#ifdef CONFIG_BT_NIMBLE_ENABLED
    uint8_t own_addr_type;
    struct ble_gap_disc_params disc_params;
    int rc;

    /* Figure out address to use while advertising (no privacy for now) */
    rc = ble_hs_id_infer_auto(0, &own_addr_type);
    if (rc != 0) {
        ESP_LOGE(TAG, "error determining address type; rc=%d\n", rc);
        return;
    }

    /* Tell the controller to filter duplicates; we don't want to process
     * repeated advertisements from the same device.
     */
    disc_params.filter_duplicates = 1;

    /**
     * Perform a passive scan.  I.e., don't send follow-up scan requests to
     * each advertiser.
     */
    disc_params.passive = 0;

    /* Use defaults for the rest of the parameters. */
    disc_params.itvl = 500;
    disc_params.window = 450;
    disc_params.filter_policy = 0;
    disc_params.limited = 0;

    ESP_LOGI(TAG, "Use nimble ble scan\n");
    rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
                      blecent_gap_event, NULL);
    if (rc != 0) {
        ESP_LOGE(TAG, "Error initiating GAP discovery procedure; rc=%d\n",
                    rc);
    }
    /* Initialize data structures to track connected peers. */
    rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
    assert(rc == 0);

	if (xTimerIsTimerActive(sScanDevTimer))
	{
		ESP_LOGI(TAG, "ScanDev timer stop!");
		if (xTimerStop(sScanDevTimer, 0) == pdFAIL)
		{
			ESP_LOGI(TAG, "ScanDev timer stop() failed");
		}
	}		
#endif

}

void AppTask::ResetToFactory(void)
{
	ESP_LOGI(TAG, "ResetToFactory");
	factory_reset();
	//chip::Server::GetInstance().ScheduleFactoryReset();
}

uint64_t last_matter_timestamp = 0;
void AppTask::FunctionHandler(AppEvent * aEvent)
{
    if (aEvent->ButtonEvent.mPinNo != APP_FUNCTION_BUTTON)
    {
        return;
    }

    // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (<
    // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the
    // APP_FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT +
    // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT All LEDs start blinking after
    // FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated.
    // To cancel factory reset: release the APP_FUNCTION_BUTTON once all LEDs
    // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT
    if (aEvent->ButtonEvent.mAction == APP_BUTTON_LONGPRESSED)
    {
        ESP_LOGW(TAG, "APP_BUTTON_LONGPRESSED");
        if ((xTaskGetTickCount() * portTICK_PERIOD_MS) < FACTORY_RESET_BUTTON_AVAIABLE_WINDOW) // 在上电调度的前20s
        {
            ESP_LOGW("yuezheng.gao", "-----kFunction_FactoryReset-----");
            // Actually trigger Factory Reset
            // sAppTask.mFunction = kFunction_NoneSelected;
            // GetAppTask().ResetToFactory();
            chip::Server::GetInstance().ScheduleFactoryReset(); // 这个不会删除 endpiont
            // esp_matter::factory_reset();    // 这个恢复出场设置会把所有的endpiont都删除
        }
        else
        {
            app_matter_open_commissioning();
        }
    }
    else if (aEvent->ButtonEvent.mAction == APP_BUTTON_RELEASED)
    {
        ESP_LOGW(TAG, "APP_BUTTON_RELEASED");
        if (!ConnectivityMgr().IsWiFiStationProvisioned())
        {
            ESP_LOGW(TAG, "Network is not provisioned, Ble advertissement enabled"); // 在配网状态下 按下按键 再次启动快速广播
            chip::DeviceLayer::PlatformMgr().LockChipStack();
            // Enable BLE advertisements
            chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow();
            ConnectivityMgr().SetBLEAdvertisingEnabled(true);
            ConnectivityMgr().SetBLEAdvertisingMode(ConnectivityMgr().kFastAdvertising);
            chip::DeviceLayer::PlatformMgr().UnlockChipStack();
        }
    }
    else if(aEvent->ButtonEvent.mAction == APP_BUTTON_DOUBLE_CLICK)
    {
        ESP_LOGW(TAG, "APP_BUTTON_DOUBLE_CLICK  the IsMatterCommissioned() = %d is wifi connected = %d",IsMatterCommissioned(),ConnectivityMgr().IsWiFiStationConnected());
        // wificonfig();
        // wifi_configuration();
        // GetAppTask().PostBlePairForWifiConnect();
        get_wifi_status();
    }
}

bool AppTask::isStartedWifiProvioning(void){
	return startedWifiProvioning;
}

void AppTask::setStartedWifiProvioning(bool value){
	startedWifiProvioning = value;
}

void AppTask::IdentifyActionEventHandler(AppEvent * aEvent)
{
	unsigned int Length;
	unsigned char *buffer;	
	PGCDate syncTime;

    //ESP_LOGI(TAG, "++++IdentifyAction: EndpointID: %u, type: %u", aEvent->IdentifyEvent.EndpointID, aEvent->IdentifyEvent.type);

	ESP_LOGE(TAG, "IdentifyActionEventHandler: EndpointID: %u, type: %u", aEvent->IdentifyEvent.EndpointID, aEvent->IdentifyEvent.type);
	if(aEvent->IdentifyEvent.type==0){
		isIdentifying =1;
		sGreenLED.Set(false);
		sRedLED.Set(true);			
	}
	else if(aEvent->IdentifyEvent.type==1){
		isIdentifying =0;
		sGreenLED.Set(false);
		sRedLED.Set(true);		
	}

	app_bridged_device_t *current_device = app_bridge_get_device_by_matter_endpointid(aEvent->IdentifyEvent.EndpointID);
	if(current_device){
		if(current_device->dev->persistent_info.device_type_id==ESP_MATTER_DOOR_LOCK_DEVICE_TYPE_ID)
		{					
			updatePgAesKey((const unsigned char *)current_device->dev_info.master_code,MASTER_CODE_LEN,(const unsigned char *)current_device->dev_info.device_uuid,(DEVICE_UUID_LEN * 2));
			//ESP_LOGI(TAG, "IdentifyActionEventHandler syncTime(before): %02x-%02x-%02x %02x:%02x:%02x", syncTime.year,syncTime.month,syncTime.day,syncTime.hour,syncTime.minute,syncTime.second);
			memset(&syncTime,0,sizeof(PGCDate));
			ESP_LOGI(TAG, "IdentifyActionEventHandler syncTime(after): %02x-%02x-%02x %02x:%02x:%02x", syncTime.year,syncTime.month,syncTime.day,syncTime.hour,syncTime.minute,syncTime.second);
			buffer = encodeCheckLockStateCmd(&Length,syncTime,PGCEnType_master,PGCCmdSrc_bt);		
			UartSendParm parm;
			parm.handler = CheckLockStateCmdHandler;
			uart_sent_ble_data((esp_bd_addr_t *)current_device->dev_addr.espnow_macaddr, buffer, Length, 10000,8,NULL,parm);
			free(buffer);
		}
	}else{
		ESP_LOGI("IdentifyActionEventHandler","current_device is NULL, identify bridge itself");
	}
}


void AppTask::LockActionEventHandler(AppEvent * aEvent)
{
   unsigned int Length;
   unsigned char *buffer;     
   app_bridged_device_t *Device=NULL;
   UartSendParm parm;
   PGCDate syncTime;


   
   ESP_LOGI(TAG, "LockActionEventHandler, lock endpoint: 0x%x, lock status: 0x%x", aEvent->LockEvent.EndpointID,aEvent->LockEvent.Action);
   uint64_t timestamp = get_timestamp_ms();
   last_matter_timestamp = timestamp;

   Device = app_bridge_get_device_by_matter_endpointid((uint16_t)aEvent->LockEvent.EndpointID);
   if(Device){
	   WakeupDoorLock(Device);
	   updatePgAesKey((const unsigned char *)Device->dev_info.master_code,MASTER_CODE_LEN,(const unsigned char *)Device->dev_info.device_uuid,(DEVICE_UUID_LEN * 2));
		setRandomData((unsigned char *)&timestamp);
		/*buffer =adapterOpenCloseCmd(PGLockType(Device->dev_info.lock_type),
	                                   (const char *)Device->dev_info.firmware_version,
	                                   &Length,
	                                   2,
	                                   (unsigned char *)Device->dev_info.password,
	                                   strlen((char *)Device->dev_info.password),
	                                   0,
	                                   0,
	                                   (bool)aEvent->LockEvent.Action,
	                                   PGCCmdSrc_alexa,
	                                   PGCEnType_alexa);*/
		buffer =adapterOpenCloseCmdType(PGCCmdType(Device->dev_info.command_type),
			                                   &Length,
			                                   2,
			                                   (unsigned char *)Device->dev_info.password,
			                                   strlen((char *)Device->dev_info.password),
			                                   0,
			                                   0,
			                                   (bool)aEvent->LockEvent.Action,
			                                   PGCCmdSrc_alexa,
			                                   PGCEnType_alexa);		
		bool unLock;
		PGCResult Result = decodeOpenCloseCmdFlag(&unLock,
                             buffer,
                             Length,
                             (const unsigned char *)Device->dev_info.master_code,
                             MASTER_CODE_LEN,
                             (const unsigned char *)Device->dev_info.device_uuid,
                             (DEVICE_UUID_LEN * 2),
                             (const unsigned char *)Device->dev_info.password,
                             strlen((char *)Device->dev_info.password));	

		if(Result.success){
			parm.command = unLock; 	
			parm.handler = CheckOpenCloseCmdHandler;
		}
		else{
			parm.handler = NULL;
		}
		uart_sent_ble_data((esp_bd_addr_t *)Device->dev_addr.espnow_macaddr, buffer, Length, 10000,2,NULL,parm);							   
		free(buffer);
   	}

}

void restartAfterProvisioning(intptr_t context)
{
	ESP_LOGI(TAG, "restartAfterProvisioning");
	if(startedWifiProvioning){
		if(ConnectivityMgr().IsWiFiStationProvisioned()){

			uint32_t free_heap_size = (uint32_t)esp_get_free_heap_size();
			if(free_heap_size<20000l){
				ESP_LOGE(TAG, "Memory is to low, restarting in 2 seconds...");
				vTaskDelay(2000 / portTICK_PERIOD_MS);
				esp_restart();
			}
			else{
				ESP_LOGE(TAG, "There is enough memory, not need to restart");
			}
		}
	}				
}

void StartRestartTimerAfterProvisioning(intptr_t context)
{
	if(startedWifiProvioning){
		if(ConnectivityMgr().IsWiFiStationProvisioned()){            
			uint32_t free_heap_size = (uint32_t)esp_get_free_heap_size();
			ESP_LOGI(TAG, "---------------------------After provisioing: heap space  %" PRIu32 " -------", free_heap_size);
			if(free_heap_size<20000l){
				if (sRestartTimer==NULL)
				    ESP_LOGE(TAG, "RestartTimer NULL");
				else{
					//xTimerStart(sRestartTimer, 0);										
    				if (xTimerIsTimerActive(sRestartTimer))
    				{
        				ESP_LOGI(TAG, "app timer already started, stop first!");
						if (xTimerStop(sRestartTimer, 0) == pdFAIL)
    					{
        					ESP_LOGI(TAG, "sRestartTimer  stop() failed");
        					return;
    					}
    				} 					
					// timer is not active, change its period to required value (== restart).
					// FreeRTOS- Block for a maximum of 100 ticks if the change period command
					// cannot immediately be sent to the timer command queue.
					if (xTimerChangePeriod(sRestartTimer, 1800000 / portTICK_PERIOD_MS, 100) != pdPASS)
					{
						ESP_LOGI(TAG, "app timer start() failed");
						return;
					}

				}
				
			}
			else{
				ESP_LOGE(TAG, "There is enough memory, not need to restart");
			}
		}
	}		
}

void AppTask::BridgedDevNumEventHandler(AppEvent * aEvent)
{	
	unsigned int Length;
	unsigned char *buffer;	
	PGCDate syncTime;
	ESP_LOGI(TAG, "BridgedDevNum: %d", aEvent->BridgedDevNumEvent.number);	
	GetAppTask().AppScheduleWork(PublishDeviceInfoReport, NULL); 
	if(aEvent->BridgedDevNumEvent.number>0){
		ScanDevFunctionTimerEventHandler(NULL);
	    if (xTimerIsTimerActive(sScanDevTimer))
	    {
	        ESP_LOGI(TAG, "ScanDev timer already started!");
            if (xTimerStop(sScanDevTimer, 0) == pdFAIL)
			{
			    ESP_LOGI(TAG, "ScanDev timer stop() failed");
			}
	    }
		ESP_LOGI(TAG, "ScanDev timer start!");
	    if (xTimerChangePeriod(sScanDevTimer, (BLEScanTimeout_MS+1000)/ portTICK_PERIOD_MS, 100) != pdPASS)
	    {
	        ESP_LOGI(TAG, "ScanDev timer start() failed");
	    }	
		
		app_bridged_device_t* current_device;
		current_device = app_bridge_get_bridged_device_list();
	    while (current_device) {
		    if ((current_device->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_LOCKLY) && current_device->dev){
				if(current_device->dev->persistent_info.device_type_id==ESP_MATTER_DOOR_LOCK_DEVICE_TYPE_ID)
				{					
					updatePgAesKey((const unsigned char *)current_device->dev_info.master_code,MASTER_CODE_LEN,(const unsigned char *)current_device->dev_info.device_uuid,(DEVICE_UUID_LEN * 2));
					//ESP_LOGI(TAG, "BridgedDevNumEventHandler syncTime(before): %02x-%02x-%02x %02x:%02x:%02x", syncTime.year,syncTime.month,syncTime.day,syncTime.hour,syncTime.minute,syncTime.second);
					memset(&syncTime,0,sizeof(PGCDate));
					ESP_LOGI(TAG, "BridgedDevNumEventHandler syncTime(after): %02x-%02x-%02x %02x:%02x:%02x", syncTime.year,syncTime.month,syncTime.day,syncTime.hour,syncTime.minute,syncTime.second);
					buffer = encodeCheckLockStateCmd(&Length,syncTime,PGCEnType_master,PGCCmdSrc_bt);		
					UartSendParm parm;
					parm.handler = CheckLockStateCmdHandler;
					uart_sent_ble_data((esp_bd_addr_t *)current_device->dev_addr.espnow_macaddr, buffer, Length, 10000,8,NULL,parm);
					free(buffer);
					InitialiseDoorLockAttributes(current_device);
					/*if(strlen(current_device->dev_info.time_zone)){
						if(setenv("TZ", current_device->dev_info.time_zone, 1)!=0)
							ESP_LOGE(TAG, "set time zone:%s error", current_device->dev_info.time_zone);
						else{
							ESP_LOGI(TAG, "set time zone:%s success", current_device->dev_info.time_zone);
   							tzset();
						}
					}	*/					
				}
				else if(current_device->dev->persistent_info.device_type_id==ESP_MATTER_CONTACT_SENSOR_DEVICE_TYPE_ID)
				{
				 	InitialiseDoorSensorAttributes(current_device);
				}
		    }
		    current_device = current_device->next;
		}
		
	}
	else{
	    if (xTimerIsTimerActive(sScanDevTimer))
	    {
	        ESP_LOGI(TAG, "ScanDev timer stop!");
            if (xTimerStop(sScanDevTimer, 0) == pdFAIL)
			{
			    ESP_LOGI(TAG, "ScanDev timer stop() failed");
			}
	    }	
	}
	//GetAppTask().AppScheduleWork(StartRestartTimerAfterProvisioning, NULL); 
}

void AppTask::ServiceInitActionEventHandler(AppEvent * aEvent)
{
   static bool Serviceinitialised=0;
   if(Serviceinitialised==0){
	   ESP_LOGI(TAG, "ServiceInitActionEventHandler, ServiceType: 0x%x", aEvent->ServiceInitEvent.ServiceType); 
	   if(aEvent->ServiceInitEvent.ServiceType == 1){
			// ESP_LOGE("RESTART_TASK", "Restarting now.");
    		// vTaskDelay(5000 / portTICK_PERIOD_MS);
    		// esp_restart();
		    app_sntp_init();
			vTaskDelay(pdMS_TO_TICKS(1000));
			ecdh_timer_init();
		    // app_mqtt_init();
		   	// if (ConnectivityMgr().IsWiFiStationProvisioned()){
		    //     sRedLED.Set(true);
		    //     sGreenLED.Set(false);    // 这里的灯亮会导致启动的时候打乱红灯的闪烁
			// }else{
			// }
			Serviceinitialised = 1;
	   	}
	   else{
   			sRedLED.Set(false);
	        sGreenLED.Set(true);
	   }	   	
   	}

}

void AppTask::MqttConnectedEventHandler(AppEvent * aEvent)
{
	if(aEvent->MqttConnectedEvent.Connected == true){
		static bool initialised=0;	
		if(initialised==0){
		    ESP_LOGI(TAG, "MqttConnectedEventHandler");  			
	   		rf_sensor_init();
			app_uart_init();
			uart_send_task_init();	
			GetAppTask().BridgedDevNumActionRequest(app_bridge_get_bridged_device_number());
			initialised = 1;
		}
		sGreenLED.Set(false);					
		set_mqtt_connected();
	}
	else{
		sGreenLED.Set(true);
		clear_secret_key();
	}
}

esp_err_t AppTask::PostMqttConnectedActionRequest(bool isConnected)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_MqttConnected;
	event.MqttConnectedEvent.Connected = isConnected;
    event.Handler           = MqttConnectedEventHandler;
    return PostEvent(&event);
}

void AppTask::PostLockActionRequest(chip::EndpointId aEndpointID, int8_t aAction)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_Lock;
    event.LockEvent.EndpointID  = aEndpointID;
    event.LockEvent.Action = aAction;
    event.Handler           = LockActionEventHandler;
    PostEvent(&event);
}

void AppTask::PostIdentifyActionRequest(chip::EndpointId aEndpointID, int8_t aType)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_Lock;
    event.IdentifyEvent.EndpointID  = aEndpointID;
    event.IdentifyEvent.type = aType;
    event.Handler           = IdentifyActionEventHandler;
    PostEvent(&event);
}

esp_err_t AppTask::PostMqttActionRequest(uint32_t len, uint8_t* buf)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_Mqtt;
    event.MqttEvent.len  = len;
    event.MqttEvent.buf = buf;
    event.Handler           = MqttEventHandler;
    return PostEvent(&event);
}

esp_err_t AppTask::PostUartActionRequest(uint32_t len, uint8_t* buf)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_Uart;
    event.UartEvent.len  = len;
    event.UartEvent.buf = buf;
    event.Handler           =UartReceiveEventHandler;
    return PostEvent(&event);
}

esp_err_t AppTask::PostRfActionRequest(uint32_t len, uint8_t* buf)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_Rf;
    event.RfEvent.len  = len;
    event.RfEvent.buf = buf;
    event.Handler           =RfReceiveEventHandler;
    return PostEvent(&event);
}

esp_err_t AppTask::PostBlePairForWifiConnect(void){
    AppEvent event;
    // event.Type              = AppEvent::kEventType_ServiceInit;
    // event.ServiceInitEvent.ServiceType  = type;
    event.Handler           =ble_pair_wifi_info_cfg;
    return PostEvent(&event);
}

esp_err_t AppTask::PostServiceInitActionRequest(uint8_t type)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_ServiceInit;
    event.ServiceInitEvent.ServiceType  = type;
    event.Handler           =ServiceInitActionEventHandler;
    return PostEvent(&event);
}

esp_err_t AppTask::BridgedDevNumActionRequest(uint8_t number)
{
    AppEvent event;
    event.Type              = AppEvent::kEventType_BridgedDev;
    event.BridgedDevNumEvent.number  = number;
    event.Handler           = BridgedDevNumEventHandler;
    return PostEvent(&event);
}

esp_err_t AppTask::PostEvent(const AppEvent * aEvent)
{

    if (sAppEventQueue != NULL)
    {
        BaseType_t status;
        if (xPortInIsrContext())
        {
            BaseType_t higherPrioTaskWoken = pdFALSE;
            status                         = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken);
        }
        else
        {
            status = xQueueSend(sAppEventQueue, aEvent, (TickType_t)1);
        }
        if (!status)
        	{
            	ESP_LOGE(TAG, "Failed to post event to app task event queue");
				return ESP_FAIL;
        	}
		else
			return ESP_OK;
    }
    else
    {
        ESP_LOGE(TAG, "Event Queue is NULL should never happen");
		return ESP_FAIL;
    }

}

void AppTask::DispatchEvent(AppEvent * aEvent)
{
    if (aEvent->Handler)
    {
		aEvent->Handler(aEvent);
    }
    else
    {
        if(aEvent->Type == AppEvent::kEventType_WorkFunct)
        	aEvent->CallWorkFunct.WorkFunct(aEvent->CallWorkFunct.Arg);
		else
        	ESP_LOGI(TAG, "Event received with no handler. Dropping event.");
    }
}

esp_err_t AppTask::AppScheduleWork(AppWorkFunct workFunct, intptr_t arg)
{

    AppEvent event;
    event.Type              		= AppEvent::kEventType_WorkFunct;
    event.CallWorkFunct.WorkFunct   = workFunct;
	event.CallWorkFunct.Arg			= arg;
	event.Handler					= NULL;
	return PostEvent(&event);	
}

void AppTask::MonitorOnlinestatus(void)
{
	app_bridged_device_t *current_device = app_bridge_get_bridged_device_list();
	if(IsTimeSynchronized()==false)
		return;
	uint64_t now = get_timestamp_ms();
	static bool offline=0;
	while (current_device) {
		if ((current_device->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_LOCKLY) && current_device->dev){
			if(current_device->dev->persistent_info.device_type_id==ESP_MATTER_DOOR_LOCK_DEVICE_TYPE_ID)
			{
				 if(current_device->dev_info.is_online &&\
				 	(current_device->dev_info.last_update_time) &&\
				 	(now - current_device->dev_info.last_update_time >1200000)){
				 	current_device->dev_info.is_online =false;				
					DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockReachableAttribute, reinterpret_cast<intptr_t>(current_device));
				 	GetAppTask().AppScheduleWork(PublishOnlineStatus, reinterpret_cast<intptr_t>(current_device));					 	
					offline = 1;
				 }
				if((offline==1)&&(current_device->dev_info.last_update_time>0)&&(now - current_device->dev_info.last_update_time > 86400000)){			
					ESP_LOGE(TAG, "Lock: %s No Response. Reset the hub", current_device->dev_info.device_uuid); 
					esp_restart();
				}
//				 if(offline == 1)
//				 	ble_scan_status_debug();
			}
			else if(current_device->dev->persistent_info.device_type_id==ESP_MATTER_CONTACT_SENSOR_DEVICE_TYPE_ID)
			{
				 if(current_device->dev_info.is_online &&\
				 	(current_device->dev_info.last_update_time) &&\
				 	(now - current_device->dev_info.last_update_time >12*3600*1000)){
				 	current_device->dev_info.is_online =false;				
					//DeviceLayer::PlatformMgr().ScheduleWork(UpdateLockReachableAttribute, reinterpret_cast<intptr_t>(current_device));
				 }
			}
		}
		current_device = current_device->next;
	}
}




void app_mqtt_process(esp_mqtt_event_handle_t event_data)
{
	ESP_LOGI(TAG, "app_mqtt_process");
	//ESP_LOGI(TAG, "TOPIC=%s", event_data->topic);
	
	uint8_t* buf = (uint8_t*) pvPortMalloc(event_data->data_len);
	if(buf){
		memcpy(buf, (uint8_t*)event_data->data, event_data->data_len);
		if(GetAppTask().PostMqttActionRequest(event_data->data_len, buf)==ESP_FAIL){
			 vPortFree(buf);
		     buf = NULL;
			}
	}else{
		ESP_LOGE(TAG, "app mqtt pvPortMalloc error");
	}
	
}

void app_mqtt_connected(bool isConnected)
{
	GetAppTask().PostMqttConnectedActionRequest(isConnected);
}

void timestamp_to_string(uint64_t timestamp, char* buffer, size_t buffer_size) {
    time_t rawtime = (time_t)timestamp;
    struct tm * timeinfo;

    timeinfo = localtime(&rawtime);

    strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", timeinfo);
}

bool needPublishLockEvent(uint16_t event_code, bool from_app){
	if (event_code == LK_EVENT_CODE_CLOSEDOOR_BY_LOCKLY)
	    return false;
    
	if (event_code == LK_EVENT_CODE_MAIN_OPEN
	    ||event_code == LK_EVENT_CODE_CLOSEDOOR_BY_AUTOMODE){
		char buf1[40];
		char buf2[40];
		uint64_t curr_timestamp = get_timestamp_ms();
		timestamp_to_string(last_matter_timestamp, buf1, sizeof(buf1));
		timestamp_to_string(curr_timestamp, buf2, sizeof(buf2));
		ESP_LOGI(TAG, "last_matter_timestamp: %s, curr_timestamp: %s", buf1, buf2);
		//ESP_LOGI(TAG, "curr_timestamp(%l) - last_matter_timestamp(%l): %l", curr_timestamp, last_matter_timestamp, curr_timestamp - last_matter_timestamp);
		//ESP_LOGI(TAG, "curr_timestamp - last_matter_timestamp: %l", curr_timestamp - last_matter_timestamp);
		if(curr_timestamp - last_matter_timestamp < 10000)
			return false;
	}

	return true;
}

chip::app::Clusters::DoorLock::OperationSourceEnum getOperationSource(uint8_t status, uint16_t event_code, bool from_app){
	chip::app::Clusters::DoorLock::OperationSourceEnum opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kKeypad;
	if( !(status & 0x01))
	    opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kManual;

	if(from_app){
		return chip::app::Clusters::DoorLock::OperationSourceEnum::kProprietaryRemote;
		last_matter_timestamp = 0;
	}

	switch(event_code) {
		case LK_EVENT_CODE_ONCE_PW:
		case LK_EVENT_CODE_KEYBOARD_OPEN:
		case LK_EVENT_CODE_KEYGUEST_OPEN:
		case LK_EVENT_CODE_KEYFAMILY_OPEN:
		case LK_EVENT_CODE_LGUESTONCE_PW:
		case LK_EVENT_CODE_LGUESTGUEST_OPEN:
		case LK_EVENT_CODE_LGUESTFAMILY_OPEN:
		case LK_EVENT_CODE_OACTIMERLIMIT_OPEN:
		case LK_EVENT_CODE_OACONETIMER_OPEN:
		case LK_EVENT_CODE_LGUESTOACTIMERLIMIT_OPEN:
		case LK_EVENT_CODE_LGUESTOACONETIMER_OPEN:
		case LK_EVENT_CODE_MULTIPLE_OPENDOOR:
		case LK_EVENT_CODE_EMPLOYEE_PASSWORD_OPENDOOR:
		case LOG_EVENT_CODE_ADMIN_MULTIPLE_OPENDOOR:
		case LOG_EVENT_CODE_STAFF_MULTIPLE_OPENDOOR:
		case LOG_EVENT_CODE_DIF_USER_MULTIPLE_OPENDOOR:
			opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kKeypad;
			break;

		case LK_EVENT_CODE_KEY_OPEN:
		case LK_EVENT_CODE_CLOSEDOOR_BY_UP_HANDLE:
		case LK_EVENT_CODE_CLOSEDOOR_BY_DOWN_HANDLE:
		case LK_EVENT_CODE_OPENDOOR_BY_DOWN_HANDLE:		
		case LOG_EVENT_CODE_VIOLENCE_OPENDOOR:
			opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kManual;
			break;

		case LK_EVENT_CODE_CLOSEDOOR_BY_TOUCHSCREEN:
		case LK_EVENT_CODE_CLOSEDOOR_BY_TOUCH_PGKEY:
		case LK_EVENT_CODE_CLOSEDOOR_BY_LOCKLY_KEY:
			opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kButton;
			break;

		case LK_EVENT_CODE_CLOSEDOOR_BY_AUTOMODE:
			opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kAuto;
			break;

		case LK_EVENT_CODE_ENTER_WELCOMEMODE:
		case LK_EVENT_CODE_EXIT_WELCOMEMODE:
			opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kSchedule;
			break;

		case LK_EVENT_CODE_RFID:
		case LK_EVENT_CODE_LGUESTRFID:
		case LK_EVENT_CODE_TPUESTRFID:
		case LOG_EVENT_CODE_EBADGE_CARD_OPENDOOR_ONE:
		case LOG_EVENT_CODE_EBADGE_CARD_OPENDOOR_MULTIPLE:
		case LK_EVENT_CODE_EMPLOYEE_RFID_OPENDOOR:
			opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kRfid;
			break;

		case LK_EVENT_CODE_FINGER:
		case LOG_EVENT_CODE_EMERGENCY_FP:
		case LK_EVENT_CODE_EMPLOYEE_FP_OPENDOOR:
			opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kBiometric;
			break;

		case LK_EVENT_CODE_ZWAVEOPENDOOR:
		case LK_EVENT_CODE_EMPLOYEE_APP_OPENDOOR:
		case LK_EVENT_CODE_UNLOCK_EXIT_BUTTON:
		case LK_EVENT_CODE_CLOSEDOOR_BY_Z_WAVEE:
		case LOG_EVENT_CODE_OPENDOOR_BY_EBADGE:
		case LOG_EVENT_CODE_CLOSEDOOR_BY_EBADGE:
		    opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kProprietaryRemote;
			break;

		default:
			break;
	}
	return opSource;
}

void UpdateLockAttribute(intptr_t context)
{
	app_bridged_device_t *device;
	uint16_t endpointId;
	device = (app_bridged_device_t *)context;
	endpointId = esp_matter::endpoint::get_id(device->dev->endpoint);
		
	node_t *node = node::get();
	endpoint_t *endpoint = endpoint::get(node, endpointId);
	cluster_t *cluster = cluster::get(endpoint, DoorLock::Id);
	attribute_t *attribute = attribute::get(cluster, DoorLock::Attributes::LockState::Id);
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    attribute::get_val(attribute, &val);
	chip::app::Clusters::DoorLock::DlLockState newLockState = chip::app::Clusters::DoorLock::DlLockState::kLocked;
	//chip::app::Clusters::DoorLock::OperationSourceEnum opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kKeypad;
    if(device->dev_info.device_status & 0x01){
		val.val.u8 = (uint8_t)chip::app::Clusters::DoorLock::DlLockState::kUnlocked;//2;
		newLockState = chip::app::Clusters::DoorLock::DlLockState::kUnlocked;
    }
	else{
		val.val.u8 = (uint8_t)chip::app::Clusters::DoorLock::DlLockState::kLocked;//1;
		//opSource = chip::app::Clusters::DoorLock::OperationSourceEnum::kManual;
	}			
	attribute::update(endpointId, DoorLock::Id, DoorLock::Attributes::LockState::Id, &val);	


	ble_broadcast_data ble_broadcast;
	if(device->dev_info.ble_broadcast_data[2]==16){
		ble_broadcast_data16_t *ble_broadcast16;			
		ble_broadcast16 = (ble_broadcast_data16_t *)device->dev_info.ble_broadcast_data;
		ble_broadcast.header = ble_broadcast16->header;			
		ble_broadcast.len = ble_broadcast16->len;
		ble_broadcast.status = ble_broadcast16->status;
		ble_broadcast.event_id = ble_broadcast16->event_id;
		ble_broadcast.pwd_id = ble_broadcast16->pwd_id;
		ble_broadcast.event_code = ble_broadcast16->event_code;
		memcpy(ble_broadcast.oac,ble_broadcast16->oac,10);
		ble_broadcast.user_id = 0xffff;			
	}
	else if(device->dev_info.ble_broadcast_data[2]==17){
		ble_broadcast_data17_t *ble_broadcast17;			
		ble_broadcast17 = (ble_broadcast_data17_t *)device->dev_info.ble_broadcast_data;		
		ble_broadcast.header = ble_broadcast17->header;			
		ble_broadcast.len = ble_broadcast17->len;
		ble_broadcast.status = ble_broadcast17->status;
		ble_broadcast.event_id = ble_broadcast17->event_id;
		ble_broadcast.pwd_id = ble_broadcast17->pwd_id;
		ble_broadcast.event_code = ble_broadcast17->event_code;
		memcpy(ble_broadcast.oac,ble_broadcast17->oac,10);					
		ble_broadcast.user_id = 0xffff;
	}
	else /*if(device->dev_info.ble_broadcast_data[2]==18)*/{
		ble_broadcast_data18_t *ble_broadcast18;			
		ble_broadcast18 = (ble_broadcast_data18_t *)device->dev_info.ble_broadcast_data;				
		ble_broadcast.header = ble_broadcast18->header;			
		ble_broadcast.len = ble_broadcast18->len;
		ble_broadcast.status = ble_broadcast18->status;
		ble_broadcast.event_id = ble_broadcast18->event_id;
		ble_broadcast.pwd_id = ble_broadcast18->pwd_id;
		ble_broadcast.event_code = ble_broadcast18->event_code;			
		ble_broadcast.user_id = ble_broadcast18->pwd_id;
		memcpy(ble_broadcast.oac,ble_broadcast18->oac,10);				
		ble_broadcast.pid_type = ble_broadcast18->pid_type;
	}

	 ESP_LOGI(TAG, "-------------------UpdateLockAttribute: status=%u--------------------------",device->dev_info.device_status);
	 ESP_LOGI(TAG, "Event: status=%u, event_id=%d, pwd_id=%d, event_code =%u, user_id=%u,pid_type=%u",
	 	ble_broadcast.status, ble_broadcast.event_id, ble_broadcast.pwd_id, ble_broadcast.event_code, ble_broadcast.user_id, ble_broadcast.pid_type);

	bool isAPP = false;
	if(device->dev_info.reserve[0]==65 //'A'
	    &&device->dev_info.reserve[1]==80 //'P'
		&&device->dev_info.reserve[2]==80) //'P'
		isAPP = true;
	esp_log_buffer_hex(TAG,device->dev_info.reserve,sizeof(device->dev_info.reserve));
    
	if(needPublishLockEvent(ble_broadcast.event_code, isAPP)){				
		DoorLock::OperationSourceEnum opSource = getOperationSource(device->dev_info.device_status,ble_broadcast.event_code, isAPP);
		chip::EndpointId aEndpointID;
		memcpy(&aEndpointID, &endpointId, sizeof(uint16_t));
		
		ESP_LOGI(TAG, "UpdateLockAttribute, endpointId:%u, aEndpointID:%u",endpointId,aEndpointID);

		Nullable<uint16_t> userIndex; 
		Nullable<List<const LockOpCredentials>> userCredentials; 
		userCredentials.SetNull();

		if (opSource == DoorLock::OperationSourceEnum::kKeypad && 
    		newLockState == DoorLock::DlLockState::kUnlocked) {
    		//userIndex = (uint16_t)ble_broadcast.pwd_id;
			userIndex.SetNonNull((uint16_t)ble_broadcast.pwd_id);
    		// 使用构造函数或方法初始化`credentials`
            LockOpCredentials userCredential[] = { { DoorLock::CredentialTypeEnum::kPin,(uint16_t)ble_broadcast.pwd_id } };
		    ESP_LOGI(TAG, "UpdateLockAttribute, userIndex:%u",userIndex.Value());
			for (const auto& credential : userCredential) {
				ESP_LOGI(TAG, "UpdateLockAttribute, credential type:%u, credential id:%u",(uint8_t)(credential.credentialType),credential.credentialIndex);
			}

            userCredentials.SetNonNull(List<const LockOpCredentials>(userCredential));			
			if(userCredentials.IsNull() == false){
				auto credentialsList = userCredentials.Value();
				for (const auto& credential : credentialsList) {
					ESP_LOGI(TAG, "UpdateLockAttribute, credential type:%u, credential id:%u",(uint8_t)(credential.credentialType),credential.credentialIndex);
				}
			}else{
				ESP_LOGI(TAG, "UpdateLockAttribute, userCredentials:NULL");
			}

		} else if (opSource == DoorLock::OperationSourceEnum::kBiometric && 
            newLockState == DoorLock::DlLockState::kUnlocked) {
    		//userIndex = (uint16_t)ble_broadcast.pwd_id;
			userIndex.SetNonNull((uint16_t)(ble_broadcast.pwd_id+100));
			ESP_LOGI(TAG, "ble_broadcast.pwd_id: %u", ble_broadcast.pwd_id);			
			uint16_t credentialIndex = ble_broadcast.pwd_id+100;
			ESP_LOGI(TAG, "UpdateLockAttribute, credentialIndex:%u",credentialIndex);
            LockOpCredentials userCredential[] = { { DoorLock::CredentialTypeEnum::kFingerprint, credentialIndex } };
            //userCredentials  = chip::app::DataModel::MakeNullable<List<const LockOpCredentials>>(userCredential);
			userCredentials.SetNonNull(List<const LockOpCredentials>(userCredential));
			if(userCredentials.IsNull() == false){
				auto credentialsList = userCredentials.Value();
				for (const auto& credential : credentialsList) {
					ESP_LOGI(TAG, "UpdateLockAttribute, credential type:%u, credential id:%u",(uint8_t)(credential.credentialType),credential.credentialIndex);
				}
			}else{
				ESP_LOGI(TAG, "UpdateLockAttribute, userCredentials:NULL");
			}

		}
		if(userIndex.IsNull() == false){
			ESP_LOGI(TAG, "UpdateLockAttribute, userIndex:%u",userIndex.Value());
		}
		else
			ESP_LOGI(TAG, "UpdateLockAttribute, userIndex:NULL, userCredentials:NULL");
		DoorLockServer::Instance().SetLockState(aEndpointID, newLockState, opSource, userIndex, userCredentials);	
	}
	//GetAppTask().AppScheduleWork(PublishDoorLockStatus, context);	 
}

void UpdateLockReachableAttribute(intptr_t context)
{
	app_bridged_device_t *device;
	uint16_t endpointId;
	device = (app_bridged_device_t *)context;
	endpointId = esp_matter::endpoint::get_id(device->dev->endpoint);		
	node_t *node = node::get();
	endpoint_t *endpoint = endpoint::get(node, endpointId);
	cluster_t *cluster = cluster::get(endpoint, BridgedDeviceBasicInformation::Id);
	attribute_t *attribute = attribute::get(cluster, BridgedDeviceBasicInformation::Attributes::Reachable::Id);
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    attribute::get_val(attribute, &val);
	val.val.b = device->dev_info.is_online;		
	attribute::update(endpointId, BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::Reachable::Id, &val);	
}

void GotRtcTime(intptr_t context)
{
	if (PlatformMgr().TryLockChipStack())
	{
		System::SystemClock().SetClock_RealTime(Microseconds64(get_timestamp_us()));	
		PlatformMgr().UnlockChipStack();
	}	
	GetAppTask().AppScheduleWork(PublishHubStatus, NULL); 
	app_mqtt_init();
}

uint32_t getFwVersionNumberFromString(uint8_t *versionStr)
{
	int major, minor, patch;
    uint32_t versionNumber = 0;

    // 解析版本号字符串
    if (sscanf(versionStr, "%d.%d.%d", &major, &minor, &patch) != 3) {
        //fprintf(stderr, "Error: Invalid version string format.\n");
		ESP_LOGE(TAG, "Error: Invalid version string format:%s .", (char*)versionStr);
        return 0;  // 返回0表示错误
    }

    // 合并版本号成一个 uint32_t 数值
    versionNumber |= (major << 16);  // 主版本号
    versionNumber |= (minor << 8);   // 次版本号
    versionNumber |= patch;          // 修订号

    return versionNumber;
}

void InitialiseDoorLockAttributes(app_bridged_device_t* device)
{
	cluster_t *cluster = cluster::get(device->dev->endpoint, DoorLock::Id);
	attribute_t *attribute = attribute::get(cluster, DoorLock::Attributes::LockState::Id);
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
	attribute::get_val(attribute, &val);
	if(val.val.u8 == (uint8_t)chip::app::Clusters::DoorLock::DlLockState::kUnlocked)
		device->dev_info.device_status |= 0x01;
	else if(val.val.u8 == (uint8_t)chip::app::Clusters::DoorLock::DlLockState::kLocked)
		device->dev_info.device_status &= ~(0x01);
/*	
	cluster = cluster::get(device->dev->endpoint, BridgedDeviceBasicInformation::Id);
	attribute = attribute::get(cluster, BridgedDeviceBasicInformation::Attributes::Reachable::Id);
	val = esp_matter_invalid(NULL);
    attribute::get_val(attribute, &val);
	device->dev_info.is_online = val.val.b;		*/
	
	ESP_LOGE(TAG, "---------------InitialiseDoorLockAttributes-------------------------");

	ESP_LOGE(TAG, "InitialiseDoorLockAttributes, lock_status:%x,is_online:%x",device->dev_info.device_status,device->dev_info.is_online);
	char VenderName[32]="Lockly";
	val = esp_matter_char_str(VenderName, strlen(VenderName));
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::VendorName::Id, &val);
	ESP_LOGI(TAG, "VenderName:%s",VenderName);

	val = esp_matter_char_str(device->dev_info.device_name, strlen(device->dev_info.device_name));
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::SerialNumber::Id, &val);
	ESP_LOGI(TAG, "SerialNumber:%s",device->dev_info.device_name);

//	char ProductName[32]="PGD628FN";
	if(strlen(device->dev_info.model)>0)
		val = esp_matter_char_str(device->dev_info.model, strlen(device->dev_info.model));	
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::ProductName::Id, &val);

	ESP_LOGI(TAG, "ProductName:%s",device->dev_info.model);

	if(strlen(device->dev_info.node_label)>0){
		val = esp_matter_char_str(device->dev_info.node_label, strlen(device->dev_info.node_label));
	}
	else{
		val = esp_matter_char_str("Lockly Smart Lock", strlen("Lockly Smart Lock"));
	}
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, &val);

    ESP_LOGI(TAG, "NodeLabel:%s",device->dev_info.node_label);	
	
    //uint32_t firmwareVersionNumber = getFwVersionNumberFromString(device->dev_info.firmware_version);
	
	//std::string firmwareVersion = device->dev_info.firmware_version;
	// std::replace(firmwareVersion.begin(), firmwareVersion.end(), '.', ' ');
	// ESP_LOGI(TAG, "Firmware Version: %s", firmwareVersion.c_str());

	// std::istringstream iss(firmwareVersion);
	// std::string versionPart;
	// uint32_t firmwareVersionNumber = 0;
	// while (std::getline(iss, versionPart, ' ')) {
	// 	uint32_t versionPartNumber = std::stoi(versionPart);
	// 	firmwareVersionNumber = (firmwareVersionNumber << 8) | versionPartNumber;
	// }
    
	//ESP_LOGI(TAG, "Firmware Version Number: %u", (unsigned long)firmwareVersionNumber);

	uint32_t hardVersionNumber = 1;
	val = esp_matter_uint32(hardVersionNumber);
	ESP_LOGE(TAG, "+++... Try to add hardware version of the bridgeed device.");
    attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::HardwareVersion::Id, &val);

	val = esp_matter_char_str("1", strlen("1"));
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::HardwareVersionString::Id, &val);
	ESP_LOGE(TAG, "HardwareVersionString:%s","1");

	uint32_t firmwareVersionNumber = 10306;
	val = esp_matter_uint32(firmwareVersionNumber);
	ESP_LOGI(TAG, "+++... Try to add software version of the bridgeed device.");
    attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::SoftwareVersion::Id, &val);
	
	val = esp_matter_char_str(device->dev_info.firmware_version, strlen(device->dev_info.firmware_version));
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::SoftwareVersionString::Id, &val);

	ESP_LOGI(TAG, "SoftwareVersionString:%s",device->dev_info.firmware_version);
	
	DeviceLayer::PlatformMgr().ScheduleWork(SetRequirePINforRemoteOperationAttribute, reinterpret_cast<intptr_t>(device));
	device->dev_info.last_update_time=0;
}

void InitialiseDoorSensorAttributes(app_bridged_device_t* device)
{
	cluster_t *cluster = cluster::get(device->dev->endpoint, BooleanState::Id);
	attribute_t *attribute = attribute::get(cluster, BooleanState::Attributes::StateValue::Id);
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    attribute::get_val(attribute, &val);
	if(val.val.b == false)
      device->dev_info.sensor_status = 0x01;
	else 
	  device->dev_info.sensor_status = 0x02;
	
	ESP_LOGI(TAG, "InitialiseDoorSensorAttributes, sensor_status:%x,is_online:%x",device->dev_info.sensor_status,device->dev_info.is_online);
	ESP_LOGI(TAG, "InitialiseDoorSensorAttributes, sensor_id:%s",(char *)device->dev_info.sensor_id);
	char VenderName[32]="Lockly";
	val = esp_matter_char_str(VenderName, strlen(VenderName));
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::VendorName::Id, &val);
	val = esp_matter_char_str(device->dev_info.sensor_id, strlen(device->dev_info.sensor_id));
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::SerialNumber::Id, &val);
	char ProductName[32]="PGA383";
	if(strcmp((char *)device->dev_info.sensor_id, "FFFFFF")==0)
		strcpy(ProductName,"PGAWDS");
	
	val = esp_matter_char_str(ProductName, strlen(ProductName));
	attribute::update(esp_matter::endpoint::get_id(device->dev->endpoint), BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::ProductName::Id, &val);
	device->dev_info.last_update_time=0;
}

void InitialiseHubAttributes(void)
{
	ESP_LOGI(TAG, "InitialiseHubAttributes");
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
	char NodeLabel[32]="LOCKLY MATTER LINK";
	val = esp_matter_char_str(NodeLabel, strlen(NodeLabel));
	attribute::update(0, BasicInformation::Id, BasicInformation::Attributes::NodeLabel::Id, &val);
}

void SetRequirePINforRemoteOperationAttribute(intptr_t context)
{
	app_bridged_device_t *device;
	uint16_t endpointId;
	device = (app_bridged_device_t *)context;
	endpointId = esp_matter::endpoint::get_id(device->dev->endpoint);
		
	node_t *node = node::get();
	endpoint_t *endpoint = endpoint::get(node, endpointId);
	cluster_t *cluster = cluster::get(endpoint, DoorLock::Id);
	attribute_t *attribute = attribute::get(cluster, DoorLock::Attributes::RequirePINforRemoteOperation::Id);
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    attribute::get_val(attribute, &val);
	val.val.b = device->dev_info.access_code_enabled;		
	attribute::update(endpointId, DoorLock::Id, DoorLock::Attributes::RequirePINforRemoteOperation::Id, &val);

	//Set other attributes
	// uint16_t numberOfSupportedUsers = 15;
	// //uint16_t numberOfSupportedCredentials = 0;
	// uint16_t numberOfPINCredentialsSupported  = 15;
	// uint8_t numberOfCredentialsSupportedPerUser = 1;
	// uint8_t numberOfWeekDaySchedulesPerUser = 15;
	// //uint8_t numberOfYearDaySchedulesPerUser = 0;
	// //uint8_t numberOfHolidaySchedules = 0;
	
	// attribute = attribute::get(cluster, DoorLock::Attributes::NumberOfTotalUsersSupported::Id);
	// val = esp_matter_invalid(NULL);
    // attribute::get_val(attribute, &val);
    // val.val.u16 = numberOfSupportedUsers;
	// attribute::update(endpointId, DoorLock::Id, DoorLock::Attributes::NumberOfTotalUsersSupported::Id, &val);
    
	// chip::EndpointId aEndpointID;
	// memcpy(&aEndpointID, &endpointId, sizeof(uint16_t));	
	// //DoorLockServer::Instance().SetNumberOfUsersSupported(aEndpointID, numberOfSupportedUsers)
	
	// attribute = attribute::get(cluster, DoorLock::Attributes::NumberOfPINUsersSupported::Id);
	// val = esp_matter_invalid(NULL);
    // attribute::get_val(attribute, &val);
    // val.val.u16 = numberOfPINCredentialsSupported;
	// attribute::update(endpointId, DoorLock::Id, DoorLock::Attributes::NumberOfPINUsersSupported::Id, &val);
	// //DoorLockServer::Instance().SetNumberOfPINUsersSupported(aEndpointID, numberOfPINCredentialsSupported)

	// //attribute = attribute::get(cluster, DoorLock::Attributes::NumberOfRFIDUsersSupported::Id);

	// attribute = attribute::get(cluster, DoorLock::Attributes::NumberOfWeekDaySchedulesSupportedPerUser::Id);
	// val = esp_matter_invalid(NULL);
    // attribute::get_val(attribute, &val);
    // val.val.u16 = numberOfWeekDaySchedulesPerUser;
	// attribute::update(endpointId, DoorLock::Id, DoorLock::Attributes::NumberOfWeekDaySchedulesSupportedPerUser::Id, &val);
    // //DoorLockServer::Instance().SetNumberOfWeekDaySchedulesSupportedPerUser(aEndpointID, numberOfWeekDaySchedulesPerUser)

	// //attribute = attribute::get(cluster, DoorLock::Attributes::NumberOfYearDaySchedulesSupportedPerUser::Id);
	// attribute = attribute::get(cluster, DoorLock::Attributes::NumberOfCredentialsSupportedPerUser::Id);
	// val = esp_matter_invalid(NULL);
	// attribute::get_val(attribute, &val);
	// val.val.u8 = numberOfCredentialsSupportedPerUser;
	// //attribute = attribute::get(cluster, DoorLock::Attributes::NumberOfHolidaySchedulesSupported::Id);
	// attribute::update(endpointId, DoorLock::Id, DoorLock::Attributes::NumberOfCredentialsSupportedPerUser::Id, &val);
	// //DoorLockServer::Instance().SetNumberOfCredentialsSupportedPerUser(aEndpointID, numberOfCredentialsSupportedPerUser)
	// if(DoorLockServer::Instance().SupportsPIN(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsPIN");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsPIN");
	
	// if(DoorLockServer::Instance().SupportsPIN(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsPIN");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsPIN");

	// if(DoorLockServer::Instance().SupportsFingers(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsFingers");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsFingers");

	// if(DoorLockServer::Instance().SupportsFace(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsFace");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsFace");

	// if(DoorLockServer::Instance().SupportsWeekDaySchedules(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsWeekDaySchedules");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsWeekDaySchedules");

	// if(DoorLockServer::Instance().SupportsYearDaySchedules(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsYearDaySchedules");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsYearDaySchedules");

	// if(DoorLockServer::Instance().SupportsHolidaySchedules(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsHolidaySchedules");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsHolidaySchedules");

	// if(DoorLockServer::Instance().SupportsUSR(aEndpointID))
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, SupportsUSR");
	// else
	// 	ESP_LOGI(TAG, "SetRequirePINforRemoteOperationAttribute, Not SupportsUSR");

}

bool GetRequirePINforRemoteOperationAttribute(app_bridged_device_t* device)
{
	uint16_t endpointId;
	endpointId = esp_matter::endpoint::get_id(device->dev->endpoint);
		
	node_t *node = node::get();
	endpoint_t *endpoint = endpoint::get(node, endpointId);
	cluster_t *cluster = cluster::get(endpoint, DoorLock::Id);
	attribute_t *attribute = attribute::get(cluster, DoorLock::Attributes::RequirePINforRemoteOperation::Id);
	esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    attribute::get_val(attribute, &val);
	device->dev_info.access_code_enabled = val.val.b;
	return val.val.b;		
}


void WakeupDoorLock(app_bridged_device_t *device)
{
	if((device)&&(device->dev_info.wakeup_ind)){
		UartSendParm parm;
		parm.handler = NULL;
		unsigned char buffer_temp[9]={0xA1,0xB2,0xC3,0xD4,0x09,0x00,0x01,0x0F,0xF3};	
		uart_sent_ble_data((esp_bd_addr_t *)device->dev_addr.espnow_macaddr, buffer_temp, sizeof(buffer_temp), 5000,6,NULL,parm); 
	}
}
